﻿using CIS.Web.Common;
using CIS.Web.Models;
using CIS.Web.Properties;
using System;
using System.Data.Entity;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using static System.Net.Mime.MediaTypeNames;

namespace CIS.Web.Controllers
{
	[AllowAnonymous]
	[RoutePrefix("Account")]
	public class AccountController : BaseDbController
	{
		public async Task<ActionResult> Login(string returnUrl)
		{
			string controller = RouteData.Values["controller"].ToString();
			string actionName = RouteData.Values["action"].ToString();
			Utility.InsertLog(LoginUser, Request.Url.ToString(), controller, actionName);

			ViewBag.ReturnUrl = returnUrl;

			var conferenceId = Request["conferenceId"];
			if (!string.IsNullOrEmpty(conferenceId))
			{
				var conferenceMaster = await DbContext.ConferenceMaster.AsNoTracking()
						.FirstOrDefaultAsync(x => x.ID == conferenceId && x.Status == ConstValues.Status.正常);
				ViewBag.Language = conferenceMaster.IsInternational ? ConstValues.Language.En : ConstValues.Language.Cn;
			}
			else
			{
				ViewBag.Language = Request.Cookies["_culture"] != null ? Request.Cookies["_culture"].Value : ConstValues.Language.Cn;
			}

			var model = Utility.GetLoginModel();
			if (Session["Model"] != null)
			{
				var loginModel = Session["Model"] as LoginViewModel;
				model.Msg = loginModel.Msg;
				model.AccountName = loginModel.AccountName;
				model.Password = loginModel.Password;

				loginModel.Msg = string.Empty;
				loginModel.AccountName = string.Empty;
				loginModel.Password = string.Empty;
				Session["Model"] = loginModel;
			}

			ValidatedCode v = new ValidatedCode();
			string code = v.CreateVerifyCode();
			model.ValidateCode = code;
			Session["ValidateCode"] = code;

			return View(model);
		}

		[Route("GetValidateCode")]
		public ActionResult GetValidateCode(string validateCode)
		{
			ValidatedCode v = new ValidatedCode();
			string code = !string.IsNullOrEmpty(validateCode) ? validateCode : v.CreateVerifyCode();
			Bitmap image = v.CreateImageCode(code);
			Session["ValidateCode"] = code;

			using (MemoryStream stream = new MemoryStream())
			{
				image.Save(stream, ImageFormat.Jpeg);
				byte[] data = new byte[stream.Length];
				stream.Seek(0, SeekOrigin.Begin);
				stream.Read(data, 0, Convert.ToInt32(stream.Length));
				Response.ContentType = "image/jpeg";
				Response.AddHeader("Content-Type", "image/jpeg");
				Response.AddHeader("Content-Disposition", "inline");

				Response.BinaryWrite(data);
				Response.Flush();
				Response.End();
				return new EmptyResult();
			}
		}

		[ValidateAntiForgeryToken]
		public async Task<ActionResult> SendPasswordMail(LoginViewModel model)
		{
			var result = await DbContext.SysUserMaster.FirstOrDefaultAsync(x => x.Mail == model.Mail);

			var loginModel = new LoginViewModel();

			if (result == null)
			{
				loginModel.Msg = Resources.MsgMailNotExist;
				Session["Model"] = loginModel;
				return RedirectToAction(nameof(AccountController.Login), nameof(AccountController).GetControllerName());
			}

			result.PasswordFailed = ConstValues.intZero;
			result.IsLocked = false;
			await DbContext.SaveChangesAsync();

			var smtpServer = ConstValues.SmtpServer;
			var mailAddress = ConstValues.MailAddress;
			var password = ConstValues.MailPassword;

			var mailServer = await DbContext.SysMailServerMaster.AsNoTracking()
					.OrderBy(x => x.Sort)
					.ThenByDescending(x => x.UpdateDate)
					.FirstOrDefaultAsync(x => x.Status == ConstValues.Status.正常);

			if (mailServer != null)
			{
				smtpServer = mailServer.MailServer;
				mailAddress = mailServer.Mail;
				password = mailServer.Password;
			}

			MailSender sender = new MailSender(smtpServer);
			MailAddress from = new MailAddress(mailAddress);
			MailAddress to = new MailAddress(result.Mail);

			MailMessage message = Utility.GetMailContent(new MailModel
			{
				MailRemark = ConstValues.MailSubject.找回密码,
				Language = result.Language,
				Mail = StringExtension.EncryptMail(model.Mail),
				Password = StringExtension.Decrypt(result.Password)
			});
			message.To.Add(to);

			var strMsg = string.Empty;
			var mailTask = Task.Run(() =>
			{
				strMsg = sender.SendMail(from, message, password);
			});
			if (string.IsNullOrEmpty(strMsg))
			{
				strMsg = Resources.GetPasswordToMail;
			}

			loginModel.Msg = strMsg;
			Session["Model"] = loginModel;
			return RedirectToAction(nameof(AccountController.Login), nameof(AccountController).GetControllerName());
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public async Task<ActionResult> CheckLogin(LoginViewModel model, string returnUrl)
		{
			string password = string.Empty;
			if (!string.IsNullOrEmpty(model.Password))
			{
				password = StringExtension.Encrypt(model.Password);
			}

			var loginUser = await DbContext.SysUserMaster
					.FirstOrDefaultAsync(x => x.UserName == model.AccountName || x.Mail == model.AccountName);

			if (loginUser == null)
			{
				return JsonCamelCase(Utility.CreateFailJsonResult(Resources.MsgUserNotExist),
						JsonRequestBehavior.AllowGet);
			}

			if (loginUser.Password != password)
			{
				var msg = Resources.MsgPasswordError;
				loginUser.PasswordFailed = !loginUser.PasswordFailed.HasValue ? 1 :
						loginUser.PasswordFailed.Value + 1;

				if (loginUser.PasswordFailed == 3 || loginUser.PasswordFailed == 4)
				{
					msg = string.Format(Resources.MsgLoginWillLock, 5 - loginUser.PasswordFailed.Value);
				}
				else if (loginUser.PasswordFailed == 5)
				{
					loginUser.IsLocked = true;
					loginUser.LockTime = DateTime.Now;
					msg = Resources.MsgLoginLock;
				}
				await DbContext.SaveChangesAsync();

				return JsonCamelCase(Utility.CreateFailJsonResult(msg),
						JsonRequestBehavior.AllowGet);
			}

			if (loginUser.IsLocked)
			{
				var lockTime = loginUser.LockTime.Value.AddHours(ConstValues.LockHours).Ticks;
				var gap = Math.Ceiling((lockTime - DateTime.Now.Ticks) / 10000000 / 3600.0);
				return JsonCamelCase(Utility.CreateFailJsonResult(string.Format(Resources.MsgLoginStatus, gap)),
						JsonRequestBehavior.AllowGet);
			}
			else if (loginUser.Status == ConstValues.Status.暂停)
			{
				return JsonCamelCase(Utility.CreateFailJsonResult(Resources.MsgActiveAccount.Replace("系统邮箱", ConstValues.MailAddress)),
						JsonRequestBehavior.AllowGet);
			}

			Session["HasLogin"] = loginUser.LastLoginTime.HasValue ? "0" : "1";

			loginUser.LastLoginIP = Utility.GetRealIP();
			loginUser.LastLoginTime = DateTime.Now;
			loginUser.PasswordFailed = ConstValues.intZero;
			loginUser.IsLocked = false;
			await DbContext.SaveChangesAsync();

			FormsAuthentication.SetAuthCookie(loginUser.UserName, model.RememberMe);
			if (model.RememberMe)
			{
				Session["Model"] = new LoginViewModel
				{
					AccountName = model.AccountName,
					Password = model.Password
				};
			}

			if (Request.Cookies["_culture"] == null)
			{
				string culture = CultureHelper.GetImplementedCulture(loginUser.Language);

				HttpCookie cookie = Request.Cookies["_culture"];
				if (cookie != null)
					cookie.Value = culture;
				else
				{
					cookie = new HttpCookie("_culture");
					cookie.Value = culture;
					cookie.Expires = DateTime.Now.AddYears(1);
				}

				Response.Cookies.Add(cookie);
			}

			var url = !string.IsNullOrEmpty(returnUrl) ? returnUrl : "/Home/Index";
			return JsonCamelCase(Utility.CreateSuccessJsonResult(url),
					JsonRequestBehavior.AllowGet);
		}

		[HttpPost]
		[ValidateAntiForgeryToken]
		public ActionResult LogOff()
		{
			FormsAuthentication.SignOut();
			return RedirectToAction(nameof(HomeController.MainIndex), nameof(HomeController).GetControllerName());
		}

		private ActionResult RedirectToLocal(string returnUrl)
		{
			if (Url.IsLocalUrl(returnUrl))
			{
				return Redirect(returnUrl);
			}
			return RedirectToAction(nameof(HomeController.Index), nameof(HomeController).GetControllerName());
		}

		public async Task<ActionResult> LoginNewsImg(string id)
		{
			var conference = await DbContext.NewsInfo.AsNoTracking().FirstOrDefaultAsync(x => x.ID == id);

			if (conference != null && !string.IsNullOrEmpty(conference.MainPic))
			{
				return File(Server.MapPath(conference.MainPic), Application.Octet, Path.GetFileName(conference.MainPic));
			}
			else
			{
				return File("~/Images/ConferenceNoPic.png", Application.Octet, Path.GetFileName("~/Images/ConferenceNoPic.png"));
			}
		}

		[Route("Activate/{Param}")]
		public async Task<ActionResult> Activate(string param)
		{
			var result = await DbContext.SysUserMaster
					.FirstOrDefaultAsync(x => x.ID == param);

			var loginModel = new LoginViewModel();

			if (result == null)
			{
				loginModel.Msg = Resources.MsgUserNotExist;
				Session["Model"] = loginModel;
				return RedirectToAction(nameof(AccountController.Login), nameof(AccountController).GetControllerName());
			}

			result.Status = ConstValues.Status.正常;
			result.PasswordFailed = ConstValues.intZero;
			result.IsLocked = false;
			await DbContext.SaveChangesAsync();

			loginModel.AccountName = result.UserName;
			loginModel.Password = StringExtension.Decrypt(result.Password);
			loginModel.Msg = Resources.MsgUserActivate;

			Session["Model"] = loginModel;
			return RedirectToAction(nameof(AccountController.Login), nameof(AccountController).GetControllerName());
		}
	}
}